#pragma once

#include <vector>
#include <pthread.h>
#include <semaphore.h>
static const int N = 50; //环形队列的大小

template<class T>
class RingQueue
{
public:
    RingQueue(int num = N)
        :_ringQueue(num)
        ,_cap(num)
        ,_p_step(0)
        ,_c_step(0)
    {
        //初始化信号量
        sem_init(&_space_sem, 0, _cap); //可生产 _cap
        sem_init(&_data_sem, 0, 0);    //可消费 0

        //初始化锁
        pthread_mutex_init(&_p_mtx, nullptr);
        pthread_mutex_init(&_c_mtx, nullptr);
    }

    ~RingQueue()
    {
        //销毁信号量
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);

        //销毁锁
        pthread_mutex_destroy(&_p_mtx);
        pthread_mutex_destroy(&_c_mtx);
    }

    //生产
    void push(const T& in)
    {
        P(&_space_sem);
        //锁的粒度要尽可能的细
        lock(&_p_mtx);
        _ringQueue[_p_step++] = in;
        _p_step %= N;
        unlock(&_p_mtx);
        V(&_data_sem);
    }

    //消费
    void pop(T* out)
    {
        P(&_data_sem);
        lock(&_c_mtx);
        *out = _ringQueue[_c_step++];
        _c_step %= N;
        unlock(&_c_mtx);
        V(&_space_sem);
    }

protected:
    //封装为 P、V 操作
    void P(sem_t* psem)
    {
        sem_wait(psem);
    }

    void V(sem_t* psem)
    {
        sem_post(psem);
    }

    //封装为 lock、unlock
    void lock(pthread_mutex_t* pmtx)
    {
        pthread_mutex_lock(pmtx);
    }

    void unlock(pthread_mutex_t* pmtx)
    {
        pthread_mutex_unlock(pmtx);
    }

private:
    std::vector<T> _ringQueue;  //环形队列
    int _cap;   //容量
    sem_t _space_sem;   //生产者的信号量
    sem_t _data_sem;   //消费者的信号量

    int _p_step;    //生产者下标
    int _c_step;    //消费者下标

    //加锁保护
    pthread_mutex_t _p_mtx;   //生产者锁
    pthread_mutex_t _c_mtx;   //消费者锁
};